package com.meeting.meetingroom_api.service.impl;

import com.meeting.meetingroom_api.constants.ErrorMessages;
import com.meeting.meetingroom_api.dto.BookingDto;
import com.meeting.meetingroom_api.entity.Booking;
import com.meeting.meetingroom_api.entity.MeetingRoom;
import com.meeting.meetingroom_api.entity.User;
import com.meeting.meetingroom_api.enums.BookingStatus;
import com.meeting.meetingroom_api.enums.RoomStatus;
import com.meeting.meetingroom_api.enums.UserRole;
import com.meeting.meetingroom_api.repository.BookingRepository;
import com.meeting.meetingroom_api.repository.MeetingRoomRepository;
import com.meeting.meetingroom_api.repository.UserRepository;
import com.meeting.meetingroom_api.service.BookingCheckService;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

@Service
public class BookingCheckServiceImpl implements BookingCheckService {

    private final BookingRepository bookingRepository;
    private final UserRepository userRepository;
    private final MeetingRoomRepository meetingRoomRepository;

    @Autowired
    public BookingCheckServiceImpl(
            BookingRepository bookingRepository,
            UserRepository userRepository,
            MeetingRoomRepository meetingRoomRepository) {
        this.bookingRepository = bookingRepository;
        this.userRepository = userRepository;
        this.meetingRoomRepository = meetingRoomRepository;
    }

    @Override
    @Transactional
    public BookingDto checkIn(Integer bookingId, Integer employeeId) {
        // 验证员工
        User employee = userRepository.findById(employeeId)
                .orElseThrow(() -> new EntityNotFoundException("找不到员工ID: " + employeeId));
        if (employee.getRole() != UserRole.employee && employee.getRole() != UserRole.admin) {
            throw new SecurityException("用户没有入场登记权限");
        }

        // 获取预订
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID: " + bookingId));

        // 验证预订状态
        if (booking.getStatus() != BookingStatus.confirmed) {
            throw new IllegalStateException("只能为已确认的预订进行入场登记");
        }

        // 验证时间
        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(booking.getStartDatetime().minusMinutes(30))) {
            throw new IllegalStateException("距离预订开始时间还有30分钟以上，不能提前入场");
        }
        if (now.isAfter(booking.getEndDatetime())) {
            throw new IllegalStateException("预订时间已过，不能入场");
        }

        // 更新预订状态
        booking.setStatus(BookingStatus.in_progress);
        booking.setCheckInTime(now);
        booking.setCheckedBy(employee);

        // 检查会议室维护状态
        MeetingRoom room = booking.getRoom();
        if (room.getStatus() == RoomStatus.maintenance) {
            // 如果会议室在维护中，不允许入场
            throw new IllegalStateException(ErrorMessages.ROOM_IN_MAINTENANCE_CANNOT_CHECKIN);
        }
        
        // 注释：会议室状态现在只通过计算得出，不再直接设置
        // room.setStatus(RoomStatus.in_use);
        // meetingRoomRepository.save(room);

        return convertToDto(bookingRepository.save(booking));
    }

    @Override
    @Transactional
    public BookingDto checkOut(Integer bookingId, Integer employeeId, String roomConditionNotes) {
        // 验证员工
        User employee = userRepository.findById(employeeId)
                .orElseThrow(() -> new EntityNotFoundException("找不到员工ID: " + employeeId));
        if (employee.getRole() != UserRole.employee && employee.getRole() != UserRole.admin) {
            throw new SecurityException("用户没有离场登记权限");
        }

        // 获取预订
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID: " + bookingId));

        // 验证预订状态
        if (booking.getStatus() != BookingStatus.in_progress) {
            throw new IllegalStateException("只能为使用中的预订进行离场登记");
        }

        // 更新预订状态
        booking.setStatus(BookingStatus.completed);
        booking.setCheckOutTime(LocalDateTime.now());
        booking.setRoomConditionNotes(roomConditionNotes);

        // 更新会议室状态 - 员工可以通过checkout设置维护状态
        MeetingRoom room = booking.getRoom();
        if (roomConditionNotes != null && !roomConditionNotes.trim().isEmpty()) {
            room.setStatus(RoomStatus.maintenance);
            meetingRoomRepository.save(room);
        } else if (room.getStatus() == RoomStatus.maintenance) {
            // 会议室已在维护中，保持维护状态
            booking.setRoomConditionNotes("会议室仍在维护中");
        } else {
            // 注释：会议室状态现在只通过计算得出，不再直接设置为available
            // room.setStatus(RoomStatus.available);
            // meetingRoomRepository.save(room);
        }

        return convertToDto(bookingRepository.save(booking));
    }

    @Override
    @Transactional
    public BookingDto forceSetMaintenance(Integer bookingId, Integer employeeId, String maintenanceNotes) {
        // 验证员工
        User employee = userRepository.findById(employeeId)
                .orElseThrow(() -> new EntityNotFoundException("找不到员工ID: " + employeeId));
        if (employee.getRole() != UserRole.employee && employee.getRole() != UserRole.admin) {
            throw new SecurityException("用户没有设置维护状态的权限");
        }

        // 获取预订
        Booking booking = bookingRepository.findById(bookingId)
                .orElseThrow(() -> new EntityNotFoundException("找不到预订ID: " + bookingId));

        // 验证预订状态
        if (booking.getStatus() != BookingStatus.completed) {
            throw new IllegalStateException("只能为已完成的预订设置维护状态");
        }

        // 强制设置会议室为维护状态
        MeetingRoom room = booking.getRoom();
        room.setStatus(RoomStatus.maintenance);
        room.setDescription(maintenanceNotes);
        meetingRoomRepository.save(room);

        // 更新预订信息
        booking.setRoomConditionNotes(maintenanceNotes);
        booking.setCheckedBy(employee);
        booking.setUpdatedAt(LocalDateTime.now());

        return convertToDto(bookingRepository.save(booking));
    }

    @Override
    public Page<BookingDto> getPendingCheckIns(Pageable pageable) {
        return bookingRepository.findByStatusAndStartDatetimeBetween(
                BookingStatus.confirmed,
                LocalDateTime.now(),
                LocalDateTime.now().plusHours(2),
                pageable
        ).map(this::convertToDto);
    }

    @Override
    public Page<BookingDto> getInProgressBookings(Pageable pageable) {
        return bookingRepository.findByStatus(BookingStatus.in_progress, pageable)
                .map(this::convertToDto);
    }

    @Override
    public Page<BookingDto> getTodayBookings(Pageable pageable) {
        LocalDateTime startOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
        return bookingRepository.findByStartDatetimeBetween(startOfDay, endOfDay, pageable)
                .map(this::convertToDto);
    }

    @Override
    public Page<BookingDto> getBookingsByDate(String date, Pageable pageable) {
        LocalDate targetDate = LocalDate.parse(date, DateTimeFormatter.ISO_DATE);
        LocalDateTime startOfDay = targetDate.atStartOfDay();
        LocalDateTime endOfDay = targetDate.atTime(LocalTime.MAX);
        return bookingRepository.findByStartDatetimeBetween(startOfDay, endOfDay, pageable)
                .map(this::convertToDto);
    }

    private BookingDto convertToDto(Booking booking) {
        if (booking == null) {
            return null;
        }

        BookingDto dto = new BookingDto();
        dto.setBookingId(booking.getBookingId());
        dto.setStartDatetime(booking.getStartDatetime());
        dto.setEndDatetime(booking.getEndDatetime());
        dto.setAttendeesCount(booking.getAttendeesCount());
        dto.setEquipmentRequired(booking.getEquipmentRequired());
        dto.setTotalPrice(booking.getTotalPrice());
        dto.setStatus(booking.getStatus());
        dto.setPaymentDeadline(booking.getPaymentDeadline());
        dto.setCheckInTime(booking.getCheckInTime());
        dto.setCheckOutTime(booking.getCheckOutTime());
        dto.setRoomConditionNotes(booking.getRoomConditionNotes());
        dto.setCreatedAt(booking.getCreatedAt());
        dto.setUpdatedAt(booking.getUpdatedAt());
        
        if (booking.getCustomer() != null) {
            dto.setCustomerId(booking.getCustomer().getUserId());
            dto.setCustomerName(booking.getCustomer().getFullName());
        }
        
        if (booking.getRoom() != null) {
            dto.setRoomId(booking.getRoom().getRoomId());
            dto.setRoomName(booking.getRoom().getName());
        }
        
        if (booking.getCheckedBy() != null) {
            dto.setCheckedById(booking.getCheckedBy().getUserId());
            dto.setCheckedByName(booking.getCheckedBy().getFullName());
        }
        
        return dto;
    }
} 